import requests
import json
import os
import qrcode
from PIL import Image
import io
import base64
from io import BytesIO
from PIL import Image
import time
import threading
import time
from logger_config import logger

class APIClient:
    def __init__(self, base_url="http://127.0.0.1:2531/v2/api"):
        self.base_url = base_url
        self.token = None
        self.uuid = None
        self.app_id = None
        self.headers = {
            'Content-Type': 'application/json',
        }
        self.islogin = False
        self.app_id_file = 'app_id.json'
        self._checking_thread = None
        
        # 获取token
        self.token = self.get_token()
        if not self.token:
            logger.error("Failed to get token")
            exit() 
        else:
            self.headers = {
                'Content-Type': 'application/json',
                'X-GEWE-TOKEN': self.token
            }
            
        # 加载保存的信息
        self.load_saved_info()
        
        # 如果有保存的信息，检查登录状态
        if self.app_id and self.uuid:
            if self.check_online():
                self.islogin = True
                logger.info(f"\n已登录成功！")
                self.start_checking_online()  # Start periodic check
                return

    def down_file(self,xml_data):
        data = {
            "appId": self.app_id,
            "type": 5,
            "xml": xml_data
        }
        url = f"{self.base_url}/message/downloadImage"
        
        logger.info(f"Request {url} data: {json.dumps(data, indent=2)}")

        resp = requests.post(url, headers=self.headers, json=data)
        logger.info(f"Response: {resp.text}")

        if resp.status_code == 200:
            logger.info(f"\n下载图片消息成功")
        else:
            logger.error(f"\n下载图片消息失败: {resp.text}")

    def down_image(self, xml_data):
        data = {
            "appId": self.app_id,
            "type": 2,
            "xml": xml_data
        }
        url = f"{self.base_url}/message/downloadImage"
        resp = requests.post(url, headers=self.headers, json=data)
        if resp.status_code == 200:
            logger.info(f"\n下载图片消息成功")
        else:
            logger.error(f"\n下载图片消息失败: {resp.text}")
        

    def load_saved_info(self):
        """加载保存的登录信息"""
        try:
            if os.path.exists('login_info.json'):
                with open('login_info.json', 'r') as f:
                    info = json.load(f)
                    self.token = info.get('token')
                    self.uuid = info.get('uuid')
                    
            if os.path.exists('app_id.json'):
                with open('app_id.json', 'r') as f:
                    info = json.load(f)
                    self.app_id = info.get('appId')
                    self.uuid = info.get('uuid')
        except Exception as e:
            logger.error(f"加载保存的信息时出错: {str(e)}")
            self.app_id = None
            self.uuid = None

    def save_app_id(self, app_id, uuid):
        """保存 app_id 和 uuid 到文件"""
        try:
            with open(self.app_id_file, 'w') as f:
                json.dump({
                    'appId': app_id,
                    'uuid': uuid
                }, f, indent=2)
            logger.info(f"\n保存appId和uuid成功")
        except Exception as e:
            logger.error(f"保存appId和uuid时出错: {str(e)}")
            
    def get_token(self):
        """获取token"""
        try:
            url = f"{self.base_url}/tools/getTokenId"
            data = {}  # 空的请求体
            if self.app_id:
                data['appId'] = self.app_id
            logger.info(f"Request {url} data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    return result['data']
            return None
        except Exception as e:
            logger.error(f"获取token时出错: {str(e)}")
            return None

    def check_login_status(self):
        """检查登录状态"""
        try:
            if not self.app_id or not self.uuid:
                logger.info("Missing app_id or uuid")
                return False
                
            url = f"{self.base_url}/login/checkLogin"
            data = {
                "appId": self.app_id,
                "uuid": self.uuid
            }
            logger.info("Checking login status...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    login_info = result['data'].get('loginInfo')
                    if login_info:
                        # 登录成功，保存wxid和appid的对应关系
                        wxid = login_info.get('wxid')
                        if wxid:
                            with open('wx_login_info.json', 'w') as f:
                                json.dump({
                                    'wxid': wxid,
                                    'app_id': self.app_id,
                                    'nickname': login_info.get('nickName'),
                                    'mobile': login_info.get('mobile')
                                }, f, indent=2)
                            logger.info(f"\n登录成功！")
                            logger.info(f"微信昵称: {login_info.get('nickName')}")
                            self.start_checking_online()  # Start periodic check after reconnection
                            return True
                return False
            else:
                logger.error(f"检查登录状态失败: {response.status_code}")
                return False
        except Exception as e:
            logger.error(f"检查登录状态时出错: {str(e)}")
            return False

    def display_qrcode(self, qr_data):
        """在控制台显示二维码并开始检查登录状态"""
        try:
            # 从base64字符串中提取图像数据
            # 移除data URL前缀
            image_data = qr_data.split(',')[1]
            # 解码base64数据
            image_bytes = base64.b64decode(image_data)
            # 从字节数据创建图像
            img = Image.open(BytesIO(image_bytes))
            
            # 保存为临时文件
            temp_file = 'temp_qrcode.jpg'
            img.save(temp_file)
            logger.info(f"二维码已保存到文件: {temp_file}")
            
            # 将图像转换为字符画
            width = img.size[0]
            height = img.size[1]
            
            # 转换为黑白图
            img = img.convert('1')  # '1' 模式表示二值图像（黑白）
            
            # 逐行扫描图像并转换为字符
            lines = []
            for y in range(0, height, 2):
                line = ""
                for x in range(0, width, 1):
                    if y < height and x < width:
                        pixel = img.getpixel((x, y))
                        # 黑白两种字符：黑色用"█"，白色用空格
                        line += "█" if pixel == 0 else " "
                lines.append(line)
                
            # 打印字符画
            logger.info("\n扫描下面的二维码登录:")
            logger.info("\n" + "\n".join(lines))
            
        except Exception as e:
            logger.error(f"显示二维码时出错: {str(e)}")

    def get_login_qrcode(self):
        """获取登录二维码"""
        try:
            url = f"{self.base_url}/login/getLoginQrCode"
            data = {"appId": self.app_id}
            if self.token:
                data['token'] = self.token
                
            logger.info("Getting login QR code...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    self.app_id = result['data'].get('appId')
                    self.uuid = result['data'].get('uuid')
                    
                    # 保存appId和uuid
                    self.save_app_id(self.app_id, self.uuid)
                    
                    return result['data'].get('qrImgBase64')
            return None
        except Exception as e:
            logger.error(f"获取登录二维码时出错: {str(e)}")
            return None

    def set_callback(self, callback_url):
        """设置回调地址"""
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False
                
            url = f"{self.base_url}/tools/setCallback"
            data = {
                "token": self.token,
                "callbackUrl": callback_url
            }
            
            logger.info("Setting callback URL...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    return True
            return False
        except Exception as e:
            logger.error(f"设置回调地址时出错: {str(e)}")
            return False
    def forward_url_batch(self, to_wxids, xml_content):
        for to_wxid in to_wxids:
            if not self.forward_url(to_wxid, xml_content):
                return False
        return True

    def forward_url(self, to_wxid, xml_content):
        """转发链接消息"""
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False
                
            url = f"{self.base_url}/message/forwardUrl"
            data = {
                "appId": self.app_id,
                "toWxid": to_wxid,
                "xml": xml_content
            }
            
            logger.info("Forwarding URL message...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    return True
            return False
        except Exception as e:
            logger.error(f"转发链接消息时出错: {str(e)}")
            return False

    def forward_video_batch(self, to_wxids, xml_content):
        for to_wxid in to_wxids:
            if not self.forward_video(to_wxid, xml_content):
                return False
        return True


    def forward_video(self, to_wxid, xml_content):
        """转发视频消息"""
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False
                
            url = f"{self.base_url}/message/forwardVideo"
            data = {
                "appId": self.app_id,
                "toWxid": to_wxid,
                "xml": xml_content
            }
            
            logger.info("Forwarding video message...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    return True
            return False
        except Exception as e:
            logger.error(f"转发链接消息时出错: {str(e)}")
            return False

    def forward_image_batch(self, to_wxids, xml_content):
        for to_wxid in to_wxids:
            if not self.forward_image(to_wxid, xml_content):
                return False
        return True

    def forward_image(self, to_wxid, xml_content):
        """转发链接消息"""
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False
                
            url = f"{self.base_url}/message/forwardImage"
            data = {
                "appId": self.app_id,
                "toWxid": to_wxid,
                "xml": xml_content
            }
            
            logger.info("Forwarding image message...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    return True
            return False
        except Exception as e:
            logger.error(f"转发图片消息时出错: {str(e)}")
            return False
            
    def check_online(self):
        """检查是否在线
        Returns:
            bool: 是否在线
        """
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False
                
            url = f"{self.base_url}/login/checkOnline"
            data = {
                "appId": self.app_id
            }
            
            logger.info("Checking online status...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result.get('ret') == 200:
                    is_online = result.get('data', False)
                    if is_online:
                        self.islogin = True
                        self.start_checking_online()
                        logger.info("\n当前在线")
                    else:
                        logger.info("\n当前离线")
                        # return self.reconnect()
                    return is_online
                else:
                    logger.error(f"在线状态检查失败: {result.get('msg', '未知错误')}")
                    return False
            else:
                logger.error(f"HTTP请求失败: {response.status_code}")
                return False
                
        except Exception as e:
            logger.error(f"检查在线状态时出错: {str(e)}")
            return False

    def start_checking_online(self):
        if self._checking_thread is not None and self._checking_thread.is_alive():
            return  # Already running

        def check_online_periodically():
            while True:
                time.sleep(60)  # Check every minute
                if not self.check_online():
                    print('Disconnected. Attempting to reconnect...')
                    if not self.reconnect():
                        print('Reconnection failed. Exiting program.')
                        exit(1)

        self._checking_thread = threading.Thread(target=check_online_periodically, daemon=True)
        self._checking_thread.start()        
    def reconnect(self):
        """检查是否在线
        Returns:
            bool: 重连是否成功
        """
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False
                
            url = f"{self.base_url}/login/reconnection"
            data = {
                "appId": self.app_id
            }
            
            logger.info("Reconnecting...")
            logger.info(f"Request data: {json.dumps(data, indent=2)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    login_info = result['data'].get('loginInfo')
                    if login_info:
                        # 登录成功，保存wxid和appid的对应关系
                        wxid = login_info.get('wxid')
                        if wxid:
                            with open('wx_login_info.json', 'w') as f:
                                json.dump({
                                    'wxid': wxid,
                                    'app_id': self.app_id,
                                    'nickname': login_info.get('nickName'),
                                    'mobile': login_info.get('mobile')
                                }, f, indent=2)
                            logger.info(f"\n登录成功！")
                            logger.info(f"微信昵称: {login_info.get('nickName')}")
                            self.start_checking_online()  # Start periodic check after reconnection
                            return True
                return False
            else:
                logger.error(f"检查登录状态失败: {response.status_code}")
                return False
        except Exception as e:
            logger.error(f"重连时出错: {str(e)}")
            return False
    
    def send_text_batch(self, to_wxids, content, ats=None):
        for to_wxid in to_wxids:
            if not self.send_text(to_wxid, content, ats):
                return False
        return True
            
    def send_text(self, to_wxid, content, ats=None):
        """发送文本消息
        Args:
            to_wxid: 接收者的微信ID
            content: 消息内容
            ats: 需要@的用户ID列表（可选）
        Returns:
            bool: 是否发送成功
            dict: 发送结果，包含消息ID等信息
        """
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False, None
                
            url = f"{self.base_url}/message/postText"
            data = {
                "appId": self.app_id,
                "toWxid": to_wxid,
                "content": content
            }
            
            # 如果有@的用户，添加到请求数据中
            if ats:
                if isinstance(ats, str):
                    data["ats"] = ats
                elif isinstance(ats, list):
                    data["ats"] = ",".join(ats)
                    
                # 确保content中包含@标记
                for at_user in (ats if isinstance(ats, list) else [ats]):
                    if f"@{at_user}" not in content:
                        content = f"@{at_user} {content}"
                data["content"] = content
            
            logger.info("发送文本消息...")
            logger.info(f"Request data: {json.dumps(data, indent=2, ensure_ascii=False)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    return True, result.get('data')
            return False, None
        except Exception as e:
            logger.error(f"发送文本消息时出错: {str(e)}")
            return False, None

    def send_img(self, to_wxid, img_url):
        """发送文本消息
        Args:
            to_wxid: 接收者的微信ID
            url: 图片文件地址
        Returns:
            bool: 是否发送成功
            dict: 发送结果，包含消息ID等信息
        """
        try:
            if not self.app_id:
                logger.error("Missing app_id")
                return False, None
                
            url = f"{self.base_url}/message/postImage"
            data = {
                "appId": self.app_id,
                "toWxid": to_wxid,
                "imgUrl": img_url
            }
            
            # 如果有@的用户，添加到请求数据中
            
            logger.info("发送图片消息...")
            logger.info(f"Request data: {json.dumps(data, indent=2, ensure_ascii=False)}")
            
            response = requests.post(url, headers=self.headers, json=data)
            logger.info(f"Response: {response.text}")
            
            if response.status_code == 200:
                result = response.json()
                if result['ret'] == 200:
                    return True, result.get('data')
            return False, None
        except Exception as e:
            logger.error(f"发送图片消息时出错: {str(e)}")
            return False, None
            
    def send_text_with_at(self, to_wxid, content, at_users):
        """发送带@的文本消息（便捷方法）
        Args:
            to_wxid: 接收者的微信ID
            content: 消息内容
            at_users: 需要@的用户ID或ID列表
        Returns:
            bool: 是否发送成功
            dict: 发送结果，包含消息ID等信息
        """
        return self.send_text(to_wxid, content, at_users)
            
def main():
    client = APIClient()
    # 如果没有登录，则获取二维码
    if not client.islogin:
        qr_data = client.get_login_qrcode()
        if qr_data:
            client.display_qrcode(qr_data)
            logger.info("\n请扫描二维码登录...")
            
            # 等待扫码并检查登录状态
            while True:
                status = client.check_login_status()
                if status:
                    break
                time.sleep(5)
        else:
            logger.error("获取二维码失败")

if __name__ == "__main__":
    main()